package com.gitee.sidihuo.platform.base;

import com.gitee.sidihuo.platform.model.ApiResult;
import com.gitee.sidihuo.platform.model.BaseResponseCodeMsg;
import com.gitee.sidihuo.utils.exception.AssertException;
import com.gitee.sidihuo.utils.exception.BizException;
import com.gitee.sidihuo.utils.exception.SysException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;


@Slf4j
public class BaseExceptionAdvice {
    /**
     * 业务异常处理类型
     */
    @ExceptionHandler(value = AssertException.class)
    public ApiResult handleAssertException(AssertException e) {
        log.warn("handleAssertException {} {} developMsg = {}", BaseResponseCodeMsg.ASSERT_FAILED.getCode(), e.getMessage(), e.getDevelopMsg());
        return ApiResult.error(BaseResponseCodeMsg.ASSERT_FAILED.getCode(), e.getMessage(), e.getDevelopMsg());
    }

    @ExceptionHandler(value = BizException.class)
    public ApiResult handleBizException(BizException e) {
        log.warn("handleBizException {} {} developMsg = {}", e.getCode(), e.getMessage(), e.getDevelopMsg());
        ApiResult apiResult = ApiResult.error(e.getResponseCodeMsg(), e.getDevelopMsg());
        return apiResult;
    }

    @ExceptionHandler(value = SysException.class)
    public ApiResult handleSysException(SysException e) {
        log.warn("handleSysException {} {} developMsg = {}", e.getCode(), e.getMessage(), e.getDevelopMsg());
        ApiResult apiResult = ApiResult.error(e.getResponseCodeMsg(), e.getDevelopMsg());
        return apiResult;
    }

    @ExceptionHandler(value = UndeclaredThrowableException.class)
    public ApiResult handleUndeclaredThrowableException(UndeclaredThrowableException e) {
        log.warn("handleUndeclaredThrowableException {} cause = ", e.getMessage(), e.getCause());
        Throwable cause = e.getCause();
        if (cause == null || cause.getCause() == null) {
            return ApiResult.error(BaseResponseCodeMsg.ERROR);
        }
        cause = cause.getCause();
        if (!(cause instanceof SysException)) {
            return ApiResult.error(BaseResponseCodeMsg.ERROR);
        }
        SysException sysException = (SysException) cause;
        if (BaseResponseCodeMsg.RATE_LIMIT.getCode() == sysException.getCode()) {
            log.warn("触发系统限流");
            return ApiResult.error(sysException.getCode(), sysException.getMessage(), sysException.getDevelopMsg());
        }
        if (BaseResponseCodeMsg.DEGRADE_CIRCUIT_BREAKER.getCode() == sysException.getCode()) {
            log.warn("触发系统熔断降级");
            return ApiResult.error(sysException.getCode(), sysException.getMessage(), sysException.getDevelopMsg());
        }
        return ApiResult.error(BaseResponseCodeMsg.ERROR);
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("handleMethodArgumentNotValidException {} {} cause = {}", new Object[]{e.getClass(), e.getMessage(), e.getCause()});
        List<FieldError> fieldErrors = e.getFieldErrors();
        if (fieldErrors == null || fieldErrors.size() == 0 || fieldErrors.get(0) == null) {
            return ApiResult.error(BaseResponseCodeMsg.PARA_VALIDATE);
        }
        FieldError fieldError = fieldErrors.get(0);
        String field = fieldError.getField();
        String defaultMessage = fieldError.getDefaultMessage();
        return ApiResult.error(BaseResponseCodeMsg.PARA_VALIDATE, field + " " + defaultMessage);
    }

    /**
     * 未知异常处理
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ApiResult handleException(Exception e) {
        log.error("handleException {} {} cause = ", e.getClass(), e.getMessage(), e.getCause());
        return ApiResult.error(BaseResponseCodeMsg.ERROR);
    }

}
